functor Frame (S : FRAME_STRUCTS) : FRAME =
struct
  open S

  structure Ir = Ir
  structure A = Assem
  structure T = Temp
  structure Types = Types

  type frame ={name : string,
               id : int,
               rettype : Ir.Types.t,
               args : int ref,
               locals : int ref,
               epilog: string,
               code : A.codeblk list option,
               pre : (A.assert * A.passert) option,
               post : (A.assert * A.passert) option,
               env : (A.aptr * A.aptr * A.etype) list option}

  type mytype = Ir.Types.t

  val slotSize = 4
  val regSize = 3 * slotSize
  
  fun newFrame fid num rettype =
      let val epilog = T.newLabel();
      in  case rettype 
           of  Types.Structt(id) => 
               {name=fid, id = num, rettype=rettype, args=ref(4*slotSize), 
                locals=ref (~regSize), epilog=epilog,
                code = NONE, pre = NONE, post = NONE, env = NONE}
             | Types.Arrayt(i, subtype) =>
               {name=fid, id = num, rettype=rettype, args=ref(4*slotSize), 
                locals=ref (~regSize), epilog=epilog,
                code = NONE, pre = NONE, post = NONE, env = NONE} 
             | _ =>
               {name=fid, id = num, rettype=rettype, args=ref(3*slotSize), 
                locals=ref (~regSize), epilog=epilog,
                code = NONE, pre = NONE, post = NONE, env = NONE}
      end 
      
  fun allocArgs (frame : frame) size =
      let val offset = !(#args frame)
          val _ = (#args frame):=(!(#args frame)+size);
      in  offset
      end
  
  fun allocLocals (f : frame) size =
      (#locals f:=(!(#locals f)-size); !(#locals f))

  fun getLocals (f : frame) = Int.abs(!(#locals f))
    
  fun getFname (f : frame) = #name f

  fun getEpilog (f : frame) = #epilog f

  fun getRetType (f : frame) = #rettype f

  fun getRegSize () = regSize
 
  fun setCode (f : frame, code) : frame = 
      {name = #name f
     , id = #id f
     , rettype = #rettype f
     , args = #args f
     , locals = #locals f
     , epilog = #epilog f
     , code = SOME code
     , pre = #pre f
     , post = #post f
     , env = #env f}

  fun getCode (frame : frame) = (#code frame)

  fun setEnv (f : frame, env) : frame = 
      {name = #name f
     , id = #id f
     , rettype = #rettype f
     , args = #args f
     , locals = #locals f
     , epilog = #epilog f
     , code = #code f
     , pre = #pre f
     , post = #post f
     , env = SOME env}

  fun getEnv (frame : frame) = (#env frame)

  fun setPre (f : frame, pre) : frame = 
      {name = #name f
     , id = #id f
     , rettype = #rettype f
     , args = #args f
     , locals = #locals f
     , epilog = #epilog f
     , code = #code f
     , pre = pre
     , post = #post f
     , env = #env f}

  fun getPre (frame :frame) = (#pre frame)
  fun getPreA (frame : frame) = 
      (case getPre frame
        of  NONE => NONE
          | SOME (p, _) => SOME p)
  fun setPost (f : frame, post) : frame = 
      {name = #name f
     , id = #id f
     , rettype = #rettype f
     , args = #args f
     , locals = #locals f
     , epilog = #epilog f
     , code = #code f
     , pre = #pre f
     , post = post
     , env = #env f}
  fun getPost (frame : frame)  = (#post frame)

  fun getPostA (frame : frame) = 
      (case getPost frame
        of  NONE => NONE
          | SOME (p, _) => SOME p)
end
